package com.deltarail.snmp.spy.main;

import java.net.InetAddress;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.ResourceBundle;

import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;

import com.deltarail.snmp.main.probe.SNMPObject;
import com.deltarail.snmp.main.probe.SNMPObjectIdentifier;
import com.deltarail.snmp.main.probe.SNMPSequence;
import com.deltarail.snmp.main.probe.SNMPVarBindList;
import com.deltarail.snmp.main.probe.SNMPv1CommunicationInterface;
import com.deltarail.snmp.spy.properties.ResultTableProperties;

import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane;
import javafx.scene.text.Text;

/**
 * 
 * Controller for the MainWindow
 *
 */

public class UIController extends AnchorPane implements Initializable, Runnable
{
	@FXML
	private Button closeApplication;
	
	@FXML
	private Button getTable;
	
	@FXML
	private Button clearTable;
	
	@FXML
	private TextField deviceAddress;
	
	@FXML
	private TextField communityUsername;
		
	@FXML
	private TextField brokerIP;
	
	@FXML
	private TableView<ResultTableProperties> resultsTable;
	
	@FXML
	private TableColumn<ResultTableProperties, String> oidColumn;
	
	@FXML
	private TableColumn<ResultTableProperties, String> valueColumn;
	
	@FXML
	private Text objectsFound;
	
	private boolean exitNow;
	
	private boolean running = false;
	
	// ===============================
	// === Initialisation ============
	// ===============================
	
	public void initialize(URL location, ResourceBundle resources)
	{		
		//Table
		oidColumn.setCellValueFactory(new PropertyValueFactory<ResultTableProperties, String>(
				"oid"));
		
		valueColumn.setCellValueFactory(new PropertyValueFactory<ResultTableProperties, String>(
				"value"));
	}	
	
	@FXML
	private void closeApp ()
	{
		System.exit(0); //Exits application
	}
	
	@FXML
	private void clearTable()
	{
		exitNow = true;
		while (running)
		{
			try 
			{
				Thread.sleep(1);
			} catch (InterruptedException e) 
			{
				e.printStackTrace();
			}
		}
		
		Platform.runLater(new Runnable() 
		{
			@Override
			public void run()
			{
				resultsTable.getItems().clear();
			}
		});
		
		//call objectCounter
		countTableRows ();
		
	}
	
	@FXML
	private void countTableRows ()
	{
	//count rows in table			
	Platform.runLater(new Runnable() 
	{
		@Override
		public void run()
		{
			int countTableRows = resultsTable.getItems().size();
			objectsFound.setText(String.valueOf(countTableRows));
		}
	});
	}
	
	@FXML
	private void getTable ()
	{
		getTable.setDisable(true);
		Thread getTableThread = new Thread(this); 
		getTableThread.start();		
	}

	@Override
	public void run() 
	{
		MqttClient mqttClient = null;
		
		running = true;
		exitNow = false;
		
		try
		
		{
			if (!brokerIP.getText().isEmpty())
			{
			mqttClient = new MqttClient("tcp://" + brokerIP.getText(), "snmp_spy");
			mqttClient.connect();
			}
			
				//Get deviceAddress
				InetAddress hostAddress = InetAddress.getByName(String.valueOf(deviceAddress.getText()));
				
				//Get communityUsername
				String getCommunityUsernameTextField = communityUsername.getText();
				
				//Set SNMP Version
				int version = 0; //SNMP v1
				
				//System.out.print(getDeviceAddressTextField); //Prints getDeviceAddressTextField to console
				//System.out.print(getCommunityUsernameTextField); //Prints getCommunityUsernameTextField to console
				//System.out.print(snmpVersion); //Prints snmpVersion to console
				
				//Connect to snmp device with community username specifying the snmp version
				SNMPv1CommunicationInterface comInterface = new SNMPv1CommunicationInterface(version, hostAddress, getCommunityUsernameTextField);
				
				String itemID = "";
				String retrievedID = "1.3.6.1.2";
				
				while (!Thread.interrupted() && !retrievedID.equals(itemID))
				{
					if (exitNow)
					{
						if (mqttClient != null && mqttClient.isConnected())
						{
							try 
							{
								mqttClient.disconnect();
							} catch (MqttException e) 
							{
								e.printStackTrace();
							}
						}
						
						comInterface.closeConnection();
						running = false;
						Platform.runLater(new Runnable() 
						{			
							@Override
							public void run() 
							{
								getTable.setDisable(false);			
							}
						});
						return;
					}
					
					itemID = retrievedID;
					
					System.out.println(" about to get next entry");
					
					SNMPVarBindList newVars = comInterface.getNextMIBEntry(itemID);
					
					System.out.println(newVars);
					System.out.println(newVars.size());
					
					SNMPSequence pair = (SNMPSequence)(newVars.getSNMPObjectAt(0));
					SNMPObjectIdentifier snmpOID = (SNMPObjectIdentifier)pair.getSNMPObjectAt(0);
					SNMPObject snmpValue = pair.getSNMPObjectAt(1);
					retrievedID = snmpOID.toString();
					
					String snmpString = snmpValue.toString();
					
					//truncate at first null character
					int nullLocation = snmpString.indexOf('\0');
					if (nullLocation >= 0)
						snmpString = snmpString.substring(0,nullLocation);
					
					System.out.print("OID: " + snmpOID + "  value: " + snmpString);
					
					final String tableValue = snmpString;
					
					//publishes message
					if (!brokerIP.getText().isEmpty())
					{
						mqttClient.publish("/snmp-spy/" + snmpOID.toString(), new MqttMessage(tableValue.getBytes()));
					}
											
					//call objectCounter
					countTableRows ();
					
					Platform.runLater(new Runnable() 
					{
						
						@Override
						public void run() 
						{
							
							 //Update your table here
							 resultsTable.getItems().add(new ResultTableProperties(snmpOID.toString(), tableValue));
							 
						}
					});
				
				

			}
			
				comInterface.closeConnection();
			

		}
		
		catch (SocketTimeoutException e)
		{
			System.out.println("Got all entries");
		}
		
		catch (Exception e)
		{
			System.out.println("Error in getTable method");
			
			e.printStackTrace();
		}
		
		if (mqttClient != null && mqttClient.isConnected())
		{
			try 
			{
				mqttClient.disconnect();
			} catch (MqttException e) 
			{
				e.printStackTrace();
			}
		}
		running = false;
		Platform.runLater(new Runnable() 
		{			
			@Override
			public void run() 
			{
				getTable.setDisable(false);			
			}
		});
		
	}

	/**
	 * @return the exitNow
	 */
	public boolean isExitNow() {
		return exitNow;
	}

	/**
	 * @param exitNow the exitNow to set
	 */
	public void setExitNow(boolean exitNow) {
		this.exitNow = exitNow;
	}

}
